#pragma once
#include <queue>
#include <cstdint>
#include "Mutex.hpp"
#include "Cond.hpp"
#include "Task.hpp"

const static uint32_t gcap = 5;

// 阻塞队列 - 共享资源需要被保护
template <typename T>
class BlockQueue
{
private:
    bool IsFull()
    {
        return _q.size() >= _cap;
    }
    bool IsEmpty()
    {
        return _q.empty();
    }

public:
    BlockQueue(uint32_t cap = gcap) : _cap(cap), _c_wait_num(0), _p_wait_num(0)
    {
        // 初始化工作
        //  pthread_mutex_init(&_lock , nullptr);
        //  pthread_cond_init(&_c_cond, nullptr);
        //  pthread_cond_init(&_p_cond, nullptr);
        // 会自动调用自定义成员函数自己的构造函数进行初始化
    }
    // 向阻塞队列中放任务、数据：生产者生产
    void Enqueue(const T &in) // 引用传参
    {
        // 访问临界资源，需要申请锁
        //  pthread_mutex_lock(&_lock);
        {
            LockGuard lockguard(&_lock); // 自动创建自动销毁 --> 自动加锁、解锁
            // 判断生产条件是否满足，不满足则去消费者的条件变量下等待
            while (IsFull()) // 为了避免伪唤醒以及pthread_cond_wait 执行失败等情况，此处使用while
            {
                _c_wait_num++;
                // pthread_cond_wait(&_c_cond , &_lock);//生产者去消费者的条件变量下等待
                // 消费者到 _c_cond 下等待，生产者到 _p_cond 下等待
                // pthread_cond_wait(&_p_cond, &_lock);
                _p_cond.Wait(_lock);
                _c_wait_num--;
            }
            // 满足生产条件
            _q.push(in);
            // 唤醒消费者
            //  pthread_cond_signal(&_p_cond);//自己条件变量下等待的就是消费者
            // pthread_cond_signal(&_c_cond);
            _c_cond.NotifyOne();
        }
        // pthread_mutex_unlock(&_lock);
    }
    void Pop(T *out) // 传址传参
    {
        // pthread_mutex_lock(&_lock);
        {
            LockGuard lockguard(&_lock);
            if (IsEmpty())
            {
                _p_wait_num++;
                // pthread_cond_wait(&_p_cond, &_lock);//消费者到生产者的条件变量下等待
                // pthread_cond_wait(&_c_cond, &_lock);
                _c_cond.Wait(_lock);
                _p_wait_num--;
            }

            *out = _q.front();
            _q.pop();
            // 唤醒生产者
            //  pthread_cond_signal(&_c_cond);//
            // pthread_cond_signal(&_p_cond);
            _p_cond.NotifyOne();
        }
        // pthread_mutex_unlock(&_lock);
    }
    ~BlockQueue()
    {
        // 销毁工作
        //  pthread_mutex_destroy(&_lock);
        //  pthread_cond_destroy(&_c_cond);
        //  pthread_cond_destroy(&_p_cond);
        // 会自动调动成员变量自己的析构函数
    }

private:
    std::queue<func_t> _q;
    uint32_t _cap;

    // pthread_mutex_t _lock;
    // pthread_cond_t _c_cond;
    // pthread_cond_t _p_cond;
    Mutex _lock;
    Cond _c_cond;
    Cond _p_cond;

    int _c_wait_num;
    int _p_wait_num;
};
